package gui.userslist;

import gui.chatarea.OpenTabListener;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.InterfaceAddress;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import network.config.NetworkConfigObserver;
import network.config.NetworkConfiguration.FeatureType;
import network.config.NetworkConfiguration.PortType;
import network.config.NetworkConfiguration.Protocol;

import controller.MessageController;

import user.LocalUser;
import user.User;

public class ChatUsersList extends JPanel implements UserTargetedListener, ListDataListener, NetworkConfigObserver {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Special class to render a user in the List.
	 * 
	 */
	private class UserCellRenderer extends JPanel implements ListCellRenderer {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		
		private JLabel labelName ;
		private JLabel labelAddress ;
		
		public UserCellRenderer () {
			this.labelName = new JLabel () ;
			this.labelAddress = new JLabel () ;
			setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)) ;
			add(this.labelName) ;
			add(this.labelAddress) ;
		}

		@Override
		public Component getListCellRendererComponent (
				JList list, Object value, int index,
				boolean isSelected, boolean cellHasFocus) {
			super.setEnabled(list.isEnabled());
	        super.setFont(list.getFont());
			User u = ((User)value) ;
			this.labelName.setText(u.getUsername()) ;
			this.labelAddress.setText(u.getAddress().getHostAddress()) ;
			String textName = u.getUsername() ;
			Color backColor = Color.WHITE ;
			Color nameColor = Color.BLACK ;
			Color addrColor = Color.GRAY ;
			if (isSelected) {
				textName = "<b>" + textName + "</b>" ;
				backColor = new Color(210, 210, 210) ;
				addrColor = Color.BLACK ;
			}
			this.labelName.setText("<html>" + textName + "</html>") ;
			this.labelName.setForeground(nameColor) ;
			this.labelAddress.setForeground(addrColor) ;
			setBackground(backColor) ;
			return this ; 
		}
		
	} ;
	
	/**
	 * Special listenner call when select list of user change
	 *
	 */
	private class UserSelectionListener implements ListSelectionListener {
		
		private UserSelectListener userSelectListener = null ;
		
		public UserSelectionListener (UserSelectListener usl) {
			this.userSelectListener = usl ;
		}
		
		@Override
		public void valueChanged(ListSelectionEvent e) {
			Set <User> selectedUsers = new HashSet <User> () ;
			for (int ind : ChatUsersList.this.list.getSelectedIndices()) {
				selectedUsers.add((User)ChatUsersList.this.model.getElementAt(ind)) ;
			}
			this.userSelectListener.userSelected(selectedUsers) ;
		}
		
	}
	
	private UsersListModel model ;
	private JList list ;
	private JLabel header ;
	private UserMouseListener mouseListener ;
	
	public ChatUsersList (MessageController msgCtrl, OpenTabListener otl) {
		super () ;
		/* Création du header. */
		this.header = new JLabel("0 utilisateur(s) en ligne.", JLabel.CENTER) ;
		this.header.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked (MouseEvent me) {
				ChatUsersList.this.list.clearSelection() ;
			}
		}) ;
		/* Création de la liste. */
		this.model = new UsersListModel() ;
		this.list = new JList(this.model) ;
		this.list.setCellRenderer(new UserCellRenderer ()) ;
		this.mouseListener = new UserMouseListener(msgCtrl, otl) ;
		this.list.addMouseListener(this.mouseListener);
		this.list.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent arg0) {
				if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE) {
					ChatUsersList.this.list.clearSelection() ;
				}
			}
		}) ;
		this.list.getModel().addListDataListener(this) ;
		/* Quelques modifs pour bien aligner le tout... */
		this.header.setAlignmentX(LEFT_ALIGNMENT) ;
		this.header.setMaximumSize(new Dimension(Short.MAX_VALUE, 50)) ;
		/* Place component. */
		JScrollPane scrollUsersList = new JScrollPane(this.list) ;
		scrollUsersList.setAlignmentX(LEFT_ALIGNMENT) ;
 		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)) ;
		add(this.header) ;
		add(scrollUsersList) ;
	}
	
	
	/**
	 * Add a listener on the item selection.
	 * 
	 * @param usl
	 */
	public void addUserSelectionListener (UserSelectListener usl) {
		this.list.getSelectionModel().addListSelectionListener (new UserSelectionListener(usl)) ;
	}

	public UsersListModel getModel () {
		return this.model ;
	}

	@Override
	public void usersTargeted (Set <String> identifiers) {
		this.list.clearSelection() ;
		if (identifiers != null && identifiers.size() > 1) {
			identifiers.remove(LocalUser.getLocalUser().getIdentifier()) ;
		}
		if (identifiers != null && !identifiers.isEmpty()) {
			int[] indices = new int[this.model.getSize()] ;
			for (int i=0; i<this.model.getSize(); i++) {
				if (identifiers.contains(((User)this.model.getElementAt(i)).getIdentifier())) {
					indices[i] = i ;
				}
				else {
					indices[i] = this.model.getSize() ; // We put a index out of bound
				}
			}
			this.list.setSelectedIndices(indices) ;
		}
	}
	
	@Override
	public void intervalAdded(ListDataEvent e) {
		this.header.setText(String.valueOf(getModel().getSize()) + " utilisateur(s) en ligne.") ;
	}

	@Override
	public void contentsChanged(ListDataEvent e) {
		this.header.setText(String.valueOf(getModel().getSize()) + " utilisateur(s) en ligne.") ;
	}

	@Override
	public void intervalRemoved(ListDataEvent e) {
		this.header.setText(String.valueOf(getModel().getSize()) + " utilisateur(s) en ligne.") ;
	}

	@Override
	public void protocolChanged(Protocol newProtocol,
			EnumMap<PortType, Integer> ports,
			ArrayList<FeatureType> unsupportedFeatures) {
		if (unsupportedFeatures.contains(FeatureType.SUB_ROOM)) {
			this.list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION) ;
		}
		else {
			this.list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION) ;
		}
		if (unsupportedFeatures.contains(FeatureType.FILE_TRANSFER)) {
			this.mouseListener.setFileTransferEnable (false) ;
		}
		else {
			this.mouseListener.setFileTransferEnable (true) ;
		}
	}

	@Override
	public void portChanged(Protocol protocol, PortType portType, int port) {
	}

	@Override
	public void interfacesChanged (Set <InterfaceAddress> interfaceAddresses) {
		
	}
	
}
